#ifndef UTIL_H
#define UTIL_H

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/buffer.h>
#include <event2/util.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <sys/stat.h>
#include <signal.h>

#if defined(_WIN32)
#include "getopt.h"
typedef int socklen_t;
#define socket_last_error() WSAGetLastError()
#define snprintf _snprintf
void socket_init();
void socket_fini();
#elif defined(__linux)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/netfilter_ipv4.h>
#define socket_last_error()  (errno)
#define socket_init() do{}while(0);
#define socket_fini() do{}while(0);
#else
#error "not supported"
#endif

struct tcp_connection
{
	bufferevent* local_bev;
	bufferevent* remote_bev;
};

tcp_connection* create_connection(size_t private_size);
void destroy_connection(tcp_connection* conn);
void log_connection_event(struct bufferevent* bev, short what);
struct bufferevent* get_peer_bufferevent(struct bufferevent* bev, struct tcp_connection* conn);
size_t relay_data(struct bufferevent* from, struct bufferevent* to);
void enable_relay(struct tcp_connection* conn);

struct evconnlistener* tcp_listen(const char* ipaddr, int port, struct event_base* evbase,
	evconnlistener_cb accept_cb, void* accept_cb_args, evconnlistener_errorcb error_cb);

struct bufferevent* tcp_connect(struct sockaddr_in* addr, struct event_base* evbase,
	bufferevent_data_cb read_cb, bufferevent_data_cb write_cb,
	bufferevent_event_cb event_cb, void* cb_args);

struct bufferevent* tcp_accept(struct event_base* evbase, evutil_socket_t fd,
	bufferevent_data_cb read_cb, bufferevent_data_cb write_cb,
	bufferevent_event_cb event_cb, void* cb_args);

char* get_local_name(struct bufferevent* bev, char* buf, size_t len);
char* get_peer_name(struct bufferevent* bev, char* buf, size_t len);
const char* get_socket_error(struct bufferevent* bev);

int get_dest_addr(struct bufferevent* bev, struct sockaddr_in* addr);

#endif

